//
// Created by 陈坚 on 2023/3/24.
//

#include "ProtoBuf.h"
#include <android/log.h>

ProtoBuf::ProtoBuf(int8_t *buf, int32_t size, bool isCopy) {
    m_size = size;
    m_position = 0;
    m_buf = buf;
    m_isCopy = isCopy;
    if(isCopy){
        m_buf = static_cast<int8_t *>(malloc(size));
        memcpy(m_buf,buf,size);
    }
}

ProtoBuf::ProtoBuf(int32_t size) {
    m_size = size;
    m_position = 0;
    m_isCopy = true;
    if(size > 0){
        m_buf = static_cast<int8_t *>(malloc(size));
    }
}

ProtoBuf::~ProtoBuf() {
    if(m_isCopy && m_buf){
        free(m_buf);
    }
    m_buf = NULL;
}

std::string ProtoBuf::readString() {
    //先读key的长度
    int32_t size = readInt();
    if(size <= (m_size - m_position) && size > 0){
        std::string result((char *)m_buf + m_position,size);
        m_position += size;
        return result;
    }
    return "";
}

int32_t ProtoBuf::readInt() {
    //先读byte
    //不能确定几个字节，如果小于等于7F，说明读int结束
    uint8_t tmp = readByte();
    if((tmp >> 7) == 0){
        return tmp;
    }
    //到这说明最高位是1，长度不止7位
    //获取低7位数据
    int32_t result = tmp & 0x7f;
    int32_t i = 1;
    do {
        //继续读
        tmp = readByte();
        result |= (tmp & 0x7f) << (7 * i++);
    }while (tmp >= 0x80);
    return result;
}

int8_t ProtoBuf::readByte(){
    if(m_position == m_size){
        return 0;
    }
    return m_buf[m_position++];
}

void ProtoBuf::writeByte(int8_t value) {
    if(m_position == m_size){
        //满了，出错了
        return;
    }
    m_buf[m_position++] = value;
}

ProtoBuf *ProtoBuf::readData() {
    //先读数据的长度
    int32_t size = readInt();
    if(size <= (m_size - m_position) && size > 0){
        ProtoBuf *data = new ProtoBuf(m_buf + m_position,size,true);
        m_position += size;
        return data;
    }
    return nullptr;
}

void ProtoBuf::writeRawInt(int32_t value) {
    while (true){
        //每次处理7位数据，如果写入的数据<=0x7f，那么使用7位就可以表示了
        if(value <= 0x7f){
            writeByte(value);
            return;
        }else{
            //大于7位，则先记录低7位，并且将最高位置1
            //1. & 0x7f 获取低7位数据
            //2. | 0x80 让最高位变成1，表示超过1个字节记录整个数据
            writeByte((value & 0x7f) | 0x80);
            //7位已经写完，处理更高位的数据
            value >>= 7;
        }
    }
}

void ProtoBuf::writeString(std::string value) {
    size_t numberOfBytes = value.size();
    writeRawInt(numberOfBytes);//先写key的长度
    memcpy(m_buf + m_position,value.data(),numberOfBytes);//再写key的内容
    m_position += numberOfBytes;
}

void ProtoBuf::writeData(ProtoBuf *data) {
    size_t numberOfBytes = data->length();
    writeRawInt(numberOfBytes);//先写value的长度
    memcpy(m_buf + m_position,data->getBuf(),numberOfBytes);//再写value的内容
    m_position += numberOfBytes;
}

int32_t ProtoBuf::computeInt32Size(int32_t value) {
    //0xffffffff表示uint最大值
    //<< 7则低7位变成0，与上value
    //如果value只要7位就够了，则结果就为0，编码只需要一个字节，否则进入其他判断
    if((value & (0xffffffff << 7)) == 0){
        return 1;
    }else if((value & (0xffffffff << 14)) == 0){
        return 2;
    }else if((value & (0xffffffff << 21)) == 0){
        return 3;
    }else if((value & (0xffffffff << 28)) == 0){
        return 4;
    }
    return 5;
}

int32_t ProtoBuf::computeItemSize(std::string key, ProtoBuf *value) {
    int32_t keyLen = key.length();
    //保存key的长度与key数据需要的字节
    int32_t size = keyLen + ProtoBuf::computeInt32Size(keyLen);
    //加上保存value的长度与value数据需要的字节
    size += value->length() + ProtoBuf::computeInt32Size(value->length());
    return size;
}

int32_t ProtoBuf::computeMapSize(std::unordered_map<std::string, ProtoBuf *> map) {
    auto iter = map.begin();
    int32_t size = 0;
    for(;iter != map.end();iter++){
        auto key = iter->first;
        auto value = iter->second;
        size += computeItemSize(key,value);
    }
    return size;
}

void ProtoBuf::writeValueInt(int32_t value) {
    int32_t valueLen = ProtoBuf::computeValueInt32Size();
    memcpy(m_buf + m_position,&value,valueLen);//再写value的内容
    m_position += valueLen;
}

int32_t ProtoBuf::readValueInt() {
    int32_t valueLen = ProtoBuf::computeValueInt32Size();
    int32_t result;
    memcpy(&result,m_buf + m_position,valueLen);//再写value的内容
    m_position += valueLen;
    return result;
}

void ProtoBuf::writeValueString(const std::string &value) {
    int32_t valueLen = length();
    memcpy(m_buf + m_position,value.data(),valueLen);//再写value的内容
    m_position += valueLen;
}

const char* ProtoBuf::readValueString() {
    int32_t valueLen = length();
    char * p = (char*)malloc(valueLen);
    memcpy(p,m_buf + m_position,valueLen);//再写value的内容
    m_position += valueLen;
    return p;
}

double_t ProtoBuf::readValueDouble() {
    int32_t valueLen = ProtoBuf::computeValueDouble64Size();
    double_t result;
    memcpy(&result,m_buf + m_position,valueLen);//再写value的内容
    m_position += valueLen;
    return result;
}

void ProtoBuf::writeValueDouble(double_t value) {
    int32_t valueLen = ProtoBuf::computeValueDouble64Size();
    memcpy(m_buf + m_position,&value,valueLen);//再写value的内容
    m_position += valueLen;
}

bool ProtoBuf::readValueBoolean() {
    int32_t valueLen = ProtoBuf::computeValueBooleanSize();
    bool result;
    memcpy(&result,m_buf + m_position,valueLen);//再写value的内容
    m_position += valueLen;
    return result;
}

void ProtoBuf::writeValueBoolean(bool value) {
    int32_t valueLen = ProtoBuf::computeValueBooleanSize();
    memcpy(m_buf + m_position,&value,valueLen);//再写value的内容
    m_position += valueLen;
}

void *ProtoBuf::readValue() {
    int32_t valueLen = length();
    void* p = malloc(valueLen);
    memcpy(p,m_buf + m_position,valueLen);//再写value的内容
    m_position += valueLen;
    return p;
}

void ProtoBuf::writeValue(const void* value) {
    int32_t valueLen = length();
    memcpy(m_buf + m_position,value,valueLen);//再写value的内容
    m_position += valueLen;
}


